package com.spzx.cart.service.impl;

import com.spzx.cart.api.domain.CartInfo;
import com.spzx.cart.service.ICartService;
import com.spzx.common.core.constant.SecurityConstants;
import com.spzx.common.core.context.SecurityContextHolder;
import com.spzx.common.core.domain.R;
import com.spzx.common.core.exception.ServiceException;
import com.spzx.product.api.RemoteProductService;
import com.spzx.product.api.domain.ProductSku;
import com.spzx.product.api.domain.vo.SkuPrice;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class CartServiceImpl implements ICartService {

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    private RemoteProductService remoteProductService;


    private String getCartKey(Long userId) {//因为重复定义把方法抽取出来
        //定义key user:userId:cart
        return "user:cart:" + userId;
    }
    @Override
    public void addToTart(Long skuId, Integer skuNum) {
        // 获取当前登录用户的id
        Long userId = SecurityContextHolder.getUserId();
        //1.构建“用户”购物车hash结构key  user：用户ID：cart
        String cartKey = getCartKey(userId);
        //2.创建Hash结构绑定操作对象（方便对hash进行操作）
        //        - 第一个泛型String是Redis key的类型
        //        - 第二个泛型String是Redis hash结构中field的类型（这里购物车中每个商品用skuId作为field）
        //        - 第三个泛型CartInfo是field对应的value的类型（购物车商品详细信息）
        BoundHashOperations<String,String,CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);
        //4.判断用户购物车中是否包含该商品 如果包含：数量进行累加(某件商品数量上限99) 不包含：新增购物车商品
        String hashKey = skuId.toString();
        Integer threshold=99;//单品数量限制
        if (hashOps.hasKey(hashKey)){//在做修改
            //4.1 说明该商品在购物车中已有，对数量进行累加 ，不能超过指定上限99
            CartInfo cartInfo = hashOps.get(hashKey);
            int totalCount = cartInfo.getSkuNum() + skuNum;
            cartInfo.setSkuNum(totalCount>threshold?threshold:totalCount);
            cartInfo.setUpdateTime(new Date());
            hashOps.put(hashKey,cartInfo);
        }else {//不在做添加
            //3.判断购物车商品种类（不同SKU）总数大于50件
            Long size = hashOps.size();
            if (size >= 50) {
                throw new RuntimeException("商品种类数量超过上限50！");
            }

            //添加
            CartInfo cartInfo = new CartInfo();
            cartInfo.setCreateTime(new Date());
            cartInfo.setUserId(userId);
            cartInfo.setSkuId(skuId);
            cartInfo.setSkuNum(skuNum);
            //远程调用商品微服务，根据skuId查询ProductSku对象
            R<ProductSku> productSkuR = remoteProductService.getProductSku(skuId, SecurityConstants.INNER);
            if (productSkuR.getCode()==R.FAIL){//判断远程接口调用是否降级处理了。
                throw new ServiceException(productSkuR.getMsg());
            }
            ProductSku productSku = productSkuR.getData();//从远程调用的里面拿数据

            cartInfo.setSkuName(productSku.getSkuName());
            cartInfo.setThumbImg(productSku.getThumbImg());
            cartInfo.setCartPrice(productSku.getSalePrice());
            cartInfo.setSkuPrice(productSku.getSalePrice());

            hashOps.put(hashKey,cartInfo);
        }
    }

    @Override//查看购物车。从Redis中获取购物车列表，并更新购物车中每个商品的实时价格（从数据库获取最新价格）
    public List<CartInfo> catList() {
        //1.准备Redis Hash类型的key
        Long userId = SecurityContextHolder.getUserId();// 获取当前登录用户的id
        String cartKey =  getCartKey(userId);
        //        - 第一个泛型String是Redis key的类型
        //        - 第二个泛型String是Redis hash结构中field的类型（这里购物车中每个商品用skuId作为field）
        //        - 第三个泛型CartInfo是field对应的value的类型（购物车商品详细信息）
        BoundHashOperations<String,String,CartInfo> hashOperations = redisTemplate.boundHashOps(cartKey);
        List<CartInfo> cartInfoList = hashOperations.values(); //从redis中获取数据旧价格数据

        //2.更新商品实时价格(注意：只需要更新JVM堆内存对象的商品最新价格，redis中数据不变)
        //2.1 批量获取商品最新价格。
        if(!CollectionUtils.isEmpty(cartInfoList)){ //判断购物车列表是否为空,如果购物车不为空，则进行商品价格的更新
            //这里使用了Stream API：
//            - stream(): 将List<CartInfo>转换成流（Stream），以便进行链式处理。
//            - map: 中间操作，将每个CartInfo对象映射为它的skuId（类型为Long）。所以经过map操作后，流中的元素从CartInfo变成了Long（skuId）。
//            - toList(): 终止操作，将流中的元素收集到一个List中。这里得到的是List<Long>，即所有skuId的列表。也可以用.collect(Collectors.toList())代替
            List<Long> skuIdList = cartInfoList.stream().map((cartInfo) -> cartInfo.getSkuId()).toList();//提取购物车中所有商品的skuId列表
            //调用远程服务（商品服务）获取这些skuId对应的最新价格
            R<List<SkuPrice>> skuPriceListR = remoteProductService.getSkuPriceList(skuIdList, SecurityConstants.INNER);
            if(R.FAIL == skuPriceListR.getCode()){//检查远程调用是否成功
                throw new ServiceException(skuPriceListR.getMsg());
            }
            List<SkuPrice> skuPriceList = skuPriceListR.getData(); //数据库最新价格

            //为了从集合skuPriceList中找数据方便，我们需要转Map
//            这里使用了Stream API：
//            - stream(): 将List<SkuPrice>转换成流。
//            - collect(Collectors.toMap(...)): 终止操作，将流中的元素收集到一个Map中。
//            - 第一个参数：SkuPrice::getSkuId 是生成Map的key的Function（即取SkuPrice对象的skuId作为key）
//            - 第二个参数：SkuPrice::getSalePrice 是生成Map的value的Function（即取SkuPrice对象的salePrice作为value）
            Map<Long, BigDecimal> skuIdToSalePriceMap = skuPriceList.stream()
                    .collect(Collectors.toMap(SkuPrice::getSkuId, SkuPrice::getSalePrice));

            //2.2更新每个实时价格
            for (CartInfo cartInfo : cartInfoList) {//遍历购物车列表，更新每个购物车项的价格
                /*skuPriceList.stream().filter((skuPrice)->{
                    return skuPrice.getSkuId().equals(cartInfo.getSkuId())
                }).findFirst().ifPresent((skuPrice)->{
                    cartInfo.setSkuPrice(skuPrice.getSalePrice());
                });*/
                cartInfo.setSkuPrice(skuIdToSalePriceMap.get(cartInfo.getSkuId()));
            }

            return cartInfoList;
        }


        return new ArrayList<>();
    }

    @Override
    public void deleteCart(Long skuId) {
        // 获取当前登录用户的id
        Long userId = SecurityContextHolder.getUserId();
        //1.构建“用户”购物车hash结构key  user：用户ID：cart
        String cartKey = getCartKey(userId);
        String hashKey = skuId.toString();
        //2.创建Hash结构绑定操作对象（方便对hash进行操作）
        BoundHashOperations<String,String,CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);

        if (hashOps.hasKey(hashKey)){
            hashOps.delete(hashKey);
        }
    }

    @Override//更新选中状态
    public void checkCart(Long skuId, Integer isChecked) {
        // 获取当前登录用户的id
        Long userId = SecurityContextHolder.getUserId();
        //1.构建“用户”购物车hash结构key  user：用户ID：cart
        String cartKey = getCartKey(userId);
        String hashKey = skuId.toString();
        //2.创建Hash结构绑定操作对象（方便对hash进行操作）
        BoundHashOperations<String,String,CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);

        if (hashOps.hasKey(hashKey)){
            CartInfo cartInfo = hashOps.get(hashKey);
            cartInfo.setIsChecked(isChecked);
            hashOps.put(hashKey,cartInfo);
        }
    }

    @Override//更新购物车商品全部选中状态
    public void allCheckCart(Integer isChecked) {
        // 获取当前登录用户的id
        Long userId = SecurityContextHolder.getUserId();
        //1.构建“用户”购物车hash结构key  user：用户ID：cart
        String cartKey = getCartKey(userId);
        //2.创建Hash结构绑定操作对象（方便对hash进行操作）
        BoundHashOperations<String,String,CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);

        if (hashOps.size()>0){
            List<CartInfo> cartInfoList = hashOps.values();
            for (CartInfo cartInfo : cartInfoList) {
                cartInfo.setIsChecked(isChecked);
                hashOps.put(cartInfo.getSkuId().toString(),cartInfo);
            }
        }
    }

    @Override//清空购物车
    public void clearCart() {
        // 获取当前登录用户的id
        Long userId = SecurityContextHolder.getUserId();
        //1.构建“用户”购物车hash结构key  user：用户ID：cart
        String cartKey = getCartKey(userId);

        if (redisTemplate.hasKey(cartKey)){
            redisTemplate.delete(cartKey);
        }

    }


    //查询用户购物车列表中选中商品列表
    @Override
    public List<CartInfo> getCartCheckedList(Long userId) {
        List<CartInfo> cartInfoList=new ArrayList<>();//创建一个新的cartInfoList集合

        String cartKey = getCartKey(userId);//调用方法获取cartkey
        List<CartInfo> cartCachInfoList=redisTemplate.opsForHash().values(cartKey);
        if (!CollectionUtils.isEmpty(cartCachInfoList)){//如果cartCachInfoList不为空则
            for (CartInfo cartInfo : cartCachInfoList) {//遍历集合
                if (cartInfo.getIsChecked() ==1){//把集合中购物车被选中的
                    cartInfoList.add(cartInfo);//加入到上面创建的cartInfoList
                }
            }
        }
        return cartInfoList;
    }


    //更新用户购物车列表价格
    @Override
    public Boolean updateCartPrice(Long userId) {
        //1.准备Redis Hash类型的key
        String cartKey =  getCartKey(userId);
        //redisTemplate.boundHashOps()创建绑定到特定Key的Hash操作对象
        BoundHashOperations<String,String,CartInfo> hashOperations = redisTemplate.boundHashOps(cartKey);
        List<CartInfo> values = hashOperations.values();//获取所有购物车商品
        if(!CollectionUtils.isEmpty(values)){//判断集合是否为空（包括`null`和空集合）

            //2.批量获取商品最新价格
            //stream()：将集合转为Stream流    map()：转换元素类型（CartInfo → Long）     toList()：收集为不可变列表
            List<Long> skuIdList = values.stream().map(CartInfo::getSkuId).toList();
            //远程服务调用，获取最新价格
            R<List<SkuPrice>> skuPriceListR = remoteProductService.getSkuPriceList(skuIdList, SecurityConstants.INNER);
            if(R.FAIL == skuPriceListR.getCode()){//调用失败降级抛异常
                throw new ServiceException(skuPriceListR.getMsg());
            }
            List<SkuPrice> skuPriceList = skuPriceListR.getData();
            //collect()：终止操作，收集结果    Collectors.toMap()：转换为Map结构
            Map<Long, BigDecimal> skuIdToSalePriceMap = skuPriceList.stream().collect(Collectors.toMap(SkuPrice::getSkuId, SkuPrice::getSalePrice));

            for (CartInfo cartInfo : values) {//遍历Redis获得的数据并set从远程调用的新的价格
                if(cartInfo.getIsChecked().intValue() == 1){
                    cartInfo.setCartPrice(skuIdToSalePriceMap.get(cartInfo.getSkuId()));// 更新两个价格字段
                    cartInfo.setSkuPrice(skuIdToSalePriceMap.get(cartInfo.getSkuId()));
                    hashOperations.put(cartInfo.getSkuId().toString(),cartInfo);// 写回Redis
                }
            }
        }
        return true;//更新成功
    }

    //删除用户购物车列表中选中商品列表
    @Override
    public Boolean deleteCartCheckedList(Long userId) {
        String cartKey = getCartKey(userId);
        BoundHashOperations<String, String, CartInfo> hashOperations = redisTemplate.boundHashOps(cartKey);
        List<CartInfo> cartCachInfoList = hashOperations.values();//获取购物车信息
        if (!CollectionUtils.isEmpty(cartCachInfoList)) {//判断是否为空
            for (CartInfo cartInfo : cartCachInfoList) {//遍历购物车集合
                // 获取选中的商品并删除！
                if (cartInfo.getIsChecked() == 1) {
                    hashOperations.delete(cartInfo.getSkuId().toString());
                }
            }
        }
        return true;//删除成功
    }
}